package cz.zcu.fav.ratdroid.activity.calendar.reservation;

import java.text.ParseException;
import java.util.Date;
import java.util.Iterator;

import org.joda.time.Duration;
import org.joda.time.LocalDate;
import org.joda.time.LocalDateTime;
import org.joda.time.LocalTime;

import android.app.AlertDialog;
import android.app.Dialog;
import android.app.TimePickerDialog;
import android.content.Context;
import android.content.Intent;
import android.graphics.Paint;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.text.format.DateFormat;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.NumberPicker;
import android.widget.Switch;
import android.widget.TextView;
import android.widget.TimePicker;
import android.widget.Toast;

import com.caldroid.CaldroidFragment;
import com.caldroid.CaldroidListener;

import cz.zcu.fav.ratdroid.R;
import cz.zcu.fav.ratdroid.activity.MenuActivity;
import cz.zcu.fav.ratdroid.activity.SimpleObjectProfileActivity;
import cz.zcu.fav.ratdroid.activity.SkeletonRestFragmentActivity;
import cz.zcu.fav.ratdroid.bean.Object;
import cz.zcu.fav.ratdroid.bean.Objects;
import cz.zcu.fav.ratdroid.bean.Period;
import cz.zcu.fav.ratdroid.bean.Reservation;
import cz.zcu.fav.ratdroid.bean.Reservations;
import cz.zcu.fav.ratdroid.service.IRestListener;
import cz.zcu.fav.ratdroid.service.RestService;

public abstract class AbstractReservationActivity extends
		SkeletonRestFragmentActivity<Reservations> implements
		NumberPicker.OnValueChangeListener, OnCheckedChangeListener
{

	private Period period;

	private Button sinceButtonDate;
	private Button toButtonDate;
	private Button sinceButtonTime;
	private Button toButtonTime;
	private Button numberOfWeeksButton;
	private Switch periodicalSwitch;
	private Switch validSwitch;
	private java.text.DateFormat timeFormat;
	private java.text.DateFormat dateFormat;
	private TextView reservationPickStatus;
	private TextView reservationReturnStatus;

	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.edit_reservation);
		if (savedInstanceState == null)
		{
			period = loadBackgroudData();
		} else
		{
			period = (Period) savedInstanceState
					.get(Period.SINGLE_PERIOD_IDENTIFIER);
		}

		timeFormat = DateFormat.getTimeFormat(this);
		dateFormat = DateFormat.getDateFormat(this);
		Date sinceDate = period.getFromDate().toDate();
		Date toDate = period.getToDate().toDate();

		sinceButtonDate = (Button) findViewById(R.id.sinceButtonDate);
		toButtonDate = (Button) findViewById(R.id.toButtonDate);
		sinceButtonTime = (Button) findViewById(R.id.sinceButtonTime);
		toButtonTime = (Button) findViewById(R.id.toButtonTime);

		numberOfWeeksButton = (Button) findViewById(R.id.numberOfWeeksValue);
		periodicalSwitch = (Switch) findViewById(R.id.reservationPeriodicalSwitch);
		validSwitch = (Switch) findViewById(R.id.periodValidSwitch);

		numberOfWeeksButton.setText(period.getReservation().getPeriodCount()
				+ "");

		sinceButtonDate.setText(dateFormat.format(sinceDate));
		toButtonDate.setText(dateFormat.format(toDate));
		sinceButtonTime.setText(timeFormat.format(sinceDate));
		toButtonTime.setText(timeFormat.format(toDate));
		validSwitch.setChecked(period.isValid());
		periodicalSwitch.setChecked(period.getReservation().isPeriodical());
		validSwitch.setChecked(period.isValid());
		periodicalSwitch.setOnCheckedChangeListener(this);
		validSwitch.setOnCheckedChangeListener(this);
		reservationPickStatus = (TextView) findViewById(R.id.reservationPickStatusValue);
		reservationReturnStatus = (TextView) findViewById(R.id.reservationReturnStatusValue);

		switch (period.getPickAction())
		{
		case PICKED:
			reservationPickStatus.setText(getString(R.string.picked));
			break;
		case NOT_PICKABLE:
			reservationPickStatus.setText(getString(R.string.notPickable));
			break;
		case NOT_PICKED:
			reservationPickStatus.setText(getString(R.string.notPicked));
			break;
		}

		switch (period.getReturnAction())
		{
		case RETURNED:
			reservationReturnStatus.setText(getString(R.string.returned));
			break;
		case NOT_RETURNABLE:
			reservationReturnStatus.setText(getString(R.string.notReturnable));
			break;
		case NOT_RETURNED:
			reservationReturnStatus.setText(getString(R.string.notReturned));
			break;
		}

		// reservationStatus.setText();
		TextView objectNameValue = (TextView) findViewById(R.id.objectNameValue);
		objectNameValue.setPaintFlags(objectNameValue.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
		objectNameValue.setText(period.getReservation().getObjectName());
		TextView userNameValue = (TextView) findViewById(R.id.userNameValue);
		userNameValue.setText(period.getReservation().getUserName());
	}

	@Override
	protected void onSaveInstanceState(Bundle outState)
	{
		super.onSaveInstanceState(outState);
		outState.putSerializable(Period.SINGLE_PERIOD_IDENTIFIER, period);
	}

	public Button getNumberOfWeeksButton()
	{
		return numberOfWeeksButton;
	}

	public Switch getPeriodicalSwitch()
	{
		return periodicalSwitch;
	}

	public abstract Period loadBackgroudData();

	public void onNumberOfWeeksButtonClick(View view)
	{
		WeeksPickerFragment newFragment = new WeeksPickerFragment();
		newFragment.setListener(this);

		newFragment.setValue(period.getReservation().getPeriodCount());
		newFragment.show(getSupportFragmentManager(), "integerPicker");
	}

	public void onSinceDateButtonClick(View buttonView) throws ParseException
	{
		LocalDateTime selectedDate = period.getFromDate();

		final Button button = (Button) buttonView;

		final CaldroidFragment dialogCaldroidFragment = setupCaldoidFragment(selectedDate);
		dialogCaldroidFragment.setMinDate(LocalDate.now().toDate());

		dialogCaldroidFragment.setCaldroidListener(new CaldroidListener()
		{
			@Override
			public void onSelectDate(Date date, View view)
			{
				button.setText(dateFormat.format(date));
				LocalDate localDate = new LocalDate(date);
				LocalTime time = period.getFromDate().toLocalTime();
				period.setFromDate(localDate.toLocalDateTime(time));
				dialogCaldroidFragment.dismiss();
			}
		});
	}

	private CaldroidFragment setupCaldoidFragment(LocalDateTime selectedDate)
	{
		final CaldroidFragment dialogCaldroidFragment = CaldroidFragment
				.newInstance(getString(R.string.setupDate),
						selectedDate.getMonthOfYear(), selectedDate.getYear());
		dialogCaldroidFragment.show(getSupportFragmentManager(),
				"CALDROID_DIALOG_FRAGMENT");

		return dialogCaldroidFragment;
	}

	public void onToDateButtonClick(View buttonView) throws ParseException
	{
		LocalDateTime selectedDate = period.getToDate();

		final Button button = (Button) buttonView;
		final CaldroidFragment dialogCaldroidFragment = setupCaldoidFragment(selectedDate);

		dialogCaldroidFragment.setMinDate(period.getFromDate().toDate());
		Duration maxDuration = org.joda.time.Duration
				.standardMinutes(getSharedPreferences(
						MenuActivity.CALENDAR_GENERAL_PREFERENCES, MODE_PRIVATE)
						.getLong(MenuActivity.MAXIMUM_PERIOD_DURATION, 0));
		dialogCaldroidFragment.setMaxDate(period.getFromDate()
				.plus(maxDuration).toDate());

		dialogCaldroidFragment.setCaldroidListener(new CaldroidListener()
		{
			@Override
			public void onSelectDate(Date date, View view)
			{

				button.setText(dateFormat.format(date));
				LocalDate localDate = new LocalDate(date);
				LocalTime time = period.getToDate().toLocalTime();
				period.setToDate(localDate.toLocalDateTime(time));
				dialogCaldroidFragment.dismiss();
			}
		});
	}

	public void onSinceTimeButtonClick(View view)
	{
		final Button button = (Button) view;
		TimePickerFragment newFragment = new TimePickerFragment();
		newFragment.setInitialTime(period.getFromDate().toLocalTime());
		newFragment.setListener(new TimePickerDialog.OnTimeSetListener()
		{
			public void onTimeSet(TimePicker view, int hourOfDay, int minute)
			{
				LocalDate prevDate = period.getFromDate().toLocalDate();
				LocalTime localTime = new LocalTime(hourOfDay, minute);
				LocalDateTime locDateTime = prevDate.toLocalDateTime(localTime);
				button.setText(timeFormat.format(locDateTime.toDate()));
				period.setFromDate(locDateTime);
				// period.set
			}
		});
		newFragment.show(getSupportFragmentManager(), "timePicker");
	}

	public void onToTimeButtonClick(View view)
	{
		final Button button = (Button) view;
		TimePickerFragment newFragment = new TimePickerFragment();
		newFragment.setInitialTime(period.getToDate().toLocalTime());
		newFragment.setListener(new TimePickerDialog.OnTimeSetListener()
		{
			public void onTimeSet(TimePicker view, int hourOfDay, int minute)
			{
				LocalDate prevDate = period.getToDate().toLocalDate();
				LocalTime localTime = new LocalTime(hourOfDay, minute);
				LocalDateTime locDateTime = prevDate.toLocalDateTime(localTime);
				button.setText(timeFormat.format(locDateTime.toDate()));
				period.setToDate(locDateTime);
			}
		});
		newFragment.show(getSupportFragmentManager(), "timePicker");
	}

	public void onValueChange(NumberPicker picker, int oldVal, int newVal)
	{
		numberOfWeeksButton.setText(newVal + "");
		period.getReservation().setPeriodCount(newVal);
	}

	public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
	{
		if (buttonView.getId() == R.id.reservationPeriodicalSwitch)
		{
			if (isChecked)
			{
				numberOfWeeksButton.setEnabled(true);
				period.getReservation().setPeriodical(true);

			} else
			{
				numberOfWeeksButton.setEnabled(false);
				period.getReservation().setPeriodCount(1);
				period.getReservation().setPeriodical(false);
				numberOfWeeksButton.setText(1 + "");
			}
			period.getReservation().setPeriodical(isChecked);
		} else if (buttonView.getId() == R.id.periodValidSwitch)
		{
			period.setValid(isChecked);
		}
	}

	public static class WeeksPickerFragment extends DialogFragment
	{
		Context context;
		NumberPicker.OnValueChangeListener listener;
		int value;

		public void setListener(NumberPicker.OnValueChangeListener listener)
		{
			this.listener = listener;
		}

		public void setValue(int value)
		{
			this.value = value;
		}

		@Override
		public Dialog onCreateDialog(Bundle savedInstanceState)
		{

			context = getActivity().getApplicationContext();
			LayoutInflater li = (LayoutInflater) context
					.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
			AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

			NumberPicker view = (NumberPicker) li.inflate(
					R.layout.number_picker, null);
			view.setMinValue(1);

			int minNumberOfWeeks = getActivity().getSharedPreferences(
					MenuActivity.CALENDAR_GENERAL_PREFERENCES, MODE_PRIVATE)
					.getInt(MenuActivity.MAXIMUM_RESERVATION_PERIODICITY, 0);

			view.setMaxValue(minNumberOfWeeks);
			view.setValue(value);
			view.setOnValueChangedListener(listener);
			builder.setView(view);

			return builder.create();
		}
	}

	public static class TimePickerFragment extends DialogFragment
	{
		TimePickerDialog.OnTimeSetListener listener;
		LocalTime initialTime;

		public void setListener(TimePickerDialog.OnTimeSetListener listener)
		{
			this.listener = listener;
		}

		public void setInitialTime(LocalTime initialTime)
		{
			this.initialTime = initialTime;
		}

		@Override
		public Dialog onCreateDialog(Bundle savedInstanceState)
		{
			// Use the current time as the default values for the picker
			int hour = initialTime.getHourOfDay();
			int minute = initialTime.getMinuteOfHour();

			// Create a new instance of TimePickerDialog and return it
			return new TimePickerDialog(getActivity(), listener, hour, minute,
					DateFormat.is24HourFormat(getActivity()));
		}

	}

	public boolean validateForm()
	{
		if (period.getFromDate().isBefore(LocalDateTime.now()))
		{
			Duration duration = new Duration(period.getFromDate().toDateTime(),
					period.getToDate().toDateTime());
			period.setFromDate(LocalDateTime.now());
			period.setToDate(period.getFromDate().plus(duration));
		}

		boolean valid = !(period.getToDate().isBefore(LocalDateTime.now()) || period
				.getFromDate().isAfter(period.getToDate()));
		if (!valid)
		{
			Toast.makeText(this, getString(R.string.notValidTimesToast),
					Toast.LENGTH_SHORT).show();
		}
		return valid;
	}

	public Period getModifiedPeriod()
	{
		return period;
	}

	public Button getSinceButtonDate()
	{
		return sinceButtonDate;
	}

	public Button getToButtonDate()
	{
		return toButtonDate;
	}

	public Button getSinceButtonTime()
	{
		return sinceButtonTime;
	}

	public Button getToButtonTime()
	{
		return toButtonTime;
	}

	public Switch getValidSwitch()
	{
		return validSwitch;
	}

	/**
	 * On object label click listener - in that case we want to show full object
	 * profile
	 * 
	 * @param v
	 */
	public void onObjectLabelClick(View v)
	{
		RestService.getInstance().getObjectsById(this,
				period.getReservation().getObjectId(),
				new IRestListener<Objects>()
				{

					public void notifyException(final Exception ex)
					{
						runOnUiThread(new Runnable()
						{
							public void run()
							{
								Toast.makeText(
										AbstractReservationActivity.this,
										ex.getMessage(), Toast.LENGTH_SHORT)
										.show();
							}
						});
					}

					public void notifyDataLoaded(Objects data)
					{
						if (data != null && !data.getObjects().isEmpty())
						{
							Intent obj = new Intent(
									AbstractReservationActivity.this,
									SimpleObjectProfileActivity.class);
							obj.putExtra(Object.SINGLE_OBJECT_IDENTIFIER, data
									.getObjects().get(0));
							startActivity(obj);
						}
					}
				});
	}

	public void notifyDataLoaded(Reservations data)
	{
		if (data != null)
		{
			Iterator<Reservation> resIt = data.getReservations().iterator();
			if (resIt.hasNext())
			{
				runOnUiThread(new Runnable()
				{
					public void run()
					{
						Toast.makeText(
								AbstractReservationActivity.this,
								AbstractReservationActivity.this
										.getString(R.string.reservationOccupiedError),
								Toast.LENGTH_SHORT).show();
					}
				});
			} else
			{
				// revalidate all previous screens
				Intent returnIntent = new Intent();
				setResult(RESULT_OK, returnIntent);
				finish();
			}
		}
	}

}
